<!DOCTYPE html>
<html>

<head>
  <title>React公共状态管理方案：redux & react-redux</title>
  <meta charset='utf-8'>
  <link href='https://cdn.maxiang.io/res-min/themes/marxico.css' rel='stylesheet'>
  <style>
    #preview-contents {
      margin-top: -20px;
    }
  </style>
</head>

<body>
  <div id='preview-contents' class='note-content'>
    <h3 id="react公共状态管理方案redux-react-redux">React公共状态管理方案：redux &amp; react-redux</h3>
    <blockquote>
      <p>前面的课程中，我们讲解了复合组件通信的两种方案：</p>
      <ul>
        <li>
          <p>基于<code>props属性</code>实现父子组件通信(或具备相同父亲的兄弟组件)</p>
        </li>
        <li>
          <p>基于<code>context上下文</code>实现祖先和后代组件间的通信(或具备相同祖先的平行组件)</p>
        </li>
      </ul>
      <p>除了以上方案，其实还可以基于<code>公共状态管理</code>实现组件间的通信问题！</p>
    </blockquote>

    <p>在Vue框架中，我们可以基于vuex实现公共状态管理！</p>
    <p><img longdesc="./1660912339546.png" alt="Alt text" title="" type="image/png" width="500"
        src=""
        class=""></p>

    <p>在React框架中，我们也有<strong>公共状态管理</strong>的解决方案：</p>
    <ul>
      <li>
        <p>redux + react-redux</p>
      </li>
      <li>
        <p>dva「redux-saga 」或 umi</p>
      </li>
      <li>
        <p>MobX</p>
      </li>
      <li>
        <p>…</p>
      </li>
    </ul>


    <h4 id="redux基础知识">Redux基础知识</h4>
    <p><a href="https://cn.redux.js.org/" target="_blank">https://cn.redux.js.org/</a></p>
    <p><strong>什么是 Redux ？</strong> <br>
      Redux 是 JavaScript 应用的状态容器，提供可预测的状态管理！ <br>
      Redux 除了和 React 一起用外，还支持其它框架；它体小精悍（只有2kB，包括依赖），却有很强大的插件扩展生态！ <br>
      Redux 提供的模式和工具使您更容易理解应用程序中的状态<code>何时、何地、为什么以及如何更新</code>，以及当这些更改发生时，您的应用程序逻辑将如何表现！</p>
    <p><strong>我什么时候应该用 Redux ？</strong> <br>
      Redux 在以下情况下更有用：</p>
    <ul>
      <li>
        <p>在应用的大量地方，都存在大量的状态</p>
      </li>
      <li>
        <p>应用状态会随着时间的推移而频繁更新</p>
      </li>
      <li>
        <p>更新该状态的逻辑可能很复杂</p>
      </li>
      <li>
        <p>中型和大型代码量的应用，很多人协同开发</p>
      </li>
    </ul>

    <p><strong>Redux 库和工具</strong> <br>
      Redux 是一个小型的独立 JS 库， 但是它通常与其他几个包一起使用： <br>
      <code>React-Redux</code> <br>
      React-Redux是我们的官方库，它让 React 组件与 Redux 有了交互，可以从 store 读取一些 state，可以通过 dispatch actions 来更新 store！ <br>
      <code>Redux Toolkit</code> <br>
      Redux Toolkit 是我们推荐的编写 Redux 逻辑的方法。 它包含我们认为对于构建 Redux 应用程序必不可少的包和函数。 Redux Toolkit 构建在我们建议的最佳实践中，简化了大多数 Redux
      任务，防止了常见错误，并使编写 Redux 应用程序变得更加容易。 <br>
      <code>Redux DevTools 拓展</code> <br>
      Redux DevTools Extension 可以显示 Redux 存储中状态随时间变化的历史记录，这允许您有效地调试应用程序。
    </p>
    <p><strong><code>redux基础工作流程</code></strong></p>
    <p><img longdesc="./1661520142925.png" alt="Alt text" title="" type="image/png" width="800"
        src=""
        class=""></p>

    <p><strong>练习DEMO</strong> <br>
      store/index.js</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> { createStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> _ <span class="hljs-keyword">from</span> <span class="hljs-string">'@/assets/utils'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// REDUCER</span>
</div><div class="hljs-line"><span class="hljs-keyword">let</span> initial = {
</div><div class="hljs-line">    <span class="hljs-attr">supNum</span>: <span class="hljs-number">0</span>,
</div><div class="hljs-line">    <span class="hljs-attr">oppNum</span>: <span class="hljs-number">0</span>
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">const</span> reducer = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reducer</span>(<span class="hljs-params">state = initial, action</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-comment">//防止直接操作原始状态对象向</span>
</div><div class="hljs-line">    state = _.clone(<span class="hljs-literal">true</span>, state);
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { type, payload = <span class="hljs-number">1</span> } = action;
</div><div class="hljs-line">    <span class="hljs-keyword">switch</span> (type) {
</div><div class="hljs-line">        <span class="hljs-keyword">case</span> <span class="hljs-string">'VOTE_SUP'</span>:
</div><div class="hljs-line">            state.supNum += payload;
</div><div class="hljs-line">            <span class="hljs-keyword">break</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">case</span> <span class="hljs-string">'VOTE_OPP'</span>:
</div><div class="hljs-line">            state.oppNum += payload;
</div><div class="hljs-line">            <span class="hljs-keyword">break</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">default</span>:
</div><div class="hljs-line">    }
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> state;
</div><div class="hljs-line">};
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// 创建容器</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> store = createStore(reducer);
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> store;
</div></code></pre>

    <p>ThemeContext.js</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> { createContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> ThemeContext = createContext();
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ThemeContext;
</div></code></pre>

    <p>index.js</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line">...
</div><div class="hljs-line">import ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'./ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> store <span class="hljs-keyword">from</span> <span class="hljs-string">'./store'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
</div><div class="hljs-line">root.render(
</div><div class="hljs-line">  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Provider</span></span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span></span>
</div><div class="hljs-line"><span class="xml">      <span class="hljs-attr">store</span></span>
</div><div class="hljs-line"><span class="xml">    }}&gt;</span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;<span class="hljs-name">Vote</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">  <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">);</span>
</div></code></pre>

    <p>views/Vote.jsx</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useContext, useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> VoteMain <span class="hljs-keyword">from</span> <span class="hljs-string">'./VoteMain'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> VoteFooter <span class="hljs-keyword">from</span> <span class="hljs-string">'./VoteFooter'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> <span class="hljs-string">'./Vote.less'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> Vote = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Vote</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> { store } = useContext(ThemeContext);
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { supNum, oppNum } = store.getState();
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 控制视图更新的办法加入到redux事件池中</span>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> [_, setRandom] = useState(<span class="hljs-number">0</span>);
</div><div class="hljs-line">    useEffect(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">const</span> unsubscribe = store.subscribe(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">            setRandom(<span class="hljs-built_in">Math</span>.random());
</div><div class="hljs-line">        });
</div><div class="hljs-line">    }, []);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"vote-box"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title"</span>&gt;</span>React真的很不错!!<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"num"</span>&gt;</span>{supNum + oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">VoteMain</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">VoteFooter</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Vote;
</div></code></pre>

    <p>views/VoteMain.jsx</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useContext, useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteMain = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteMain</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> { store } = useContext(ThemeContext);
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { supNum, oppNum } = store.getState();
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> [_, setRandom] = useState(<span class="hljs-number">0</span>);
</div><div class="hljs-line">    useEffect(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">const</span> unsubscribe = store.subscribe(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">            setRandom(<span class="hljs-built_in">Math</span>.random());
</div><div class="hljs-line">        });
</div><div class="hljs-line">    }, []);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持人数：{supNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>反对人数：{oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteMain;
</div></code></pre>

    <p>views/VoteFooter.jsx</p>



    <pre class="prettyprint hljs-dark"><code class="hljs javascript"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteFooter = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteFooter</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> { store } = useContext(ThemeContext);
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"footer"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {</span>
</div><div class="hljs-line"><span class="xml">            store.dispatch({</span>
</div><div class="hljs-line"><span class="xml">                type: 'VOTE_SUP',</span>
</div><div class="hljs-line"><span class="xml">                payload: 10</span>
</div><div class="hljs-line"><span class="xml">            });</span>
</div><div class="hljs-line"><span class="xml">        }}&gt;支持<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml"></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {</span>
</div><div class="hljs-line"><span class="xml">            store.dispatch({</span>
</div><div class="hljs-line"><span class="xml">                type: 'VOTE_OPP'</span>
</div><div class="hljs-line"><span class="xml">            });</span>
</div><div class="hljs-line"><span class="xml">        }}&gt;反对<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteFooter;
</div></code></pre>

    <h4 id="redux源码解读">Redux源码解读</h4>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> _ <span class="hljs-keyword">from</span> <span class="hljs-string">'@/assets/utils'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createStore = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createStore</span>(<span class="hljs-params">reducer</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> state,
</div><div class="hljs-line">        listeners = [];
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 获取状态</span>
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> getState = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getState</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> _.clone(<span class="hljs-literal">true</span>, state);
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 事件池管理</span>
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> subscribe = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">subscribe</span>(<span class="hljs-params">listener</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> listener !== <span class="hljs-string">'function'</span>) {
</div><div class="hljs-line">            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Expected the listener to be a function.`</span>);
</div><div class="hljs-line">        }
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (listeners.some(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item === listener)) <span class="hljs-keyword">return</span>;
</div><div class="hljs-line">        listeners.push(listener);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">            listeners.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item !== listener);
</div><div class="hljs-line">        };
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 任务派发</span>
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> dispatch = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">disptach</span>(<span class="hljs-params">action</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (!_.isPlainObject(action)) {
</div><div class="hljs-line">            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Actions must be plain objects."</span>);
</div><div class="hljs-line">        }
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> action.type === <span class="hljs-string">'undefined'</span>) {
</div><div class="hljs-line">            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Actions may not have an undefined "type" property. You may have misspelled an action type string constant.'</span>);
</div><div class="hljs-line">        }
</div><div class="hljs-line">        <span class="hljs-comment">// 修改状态</span>
</div><div class="hljs-line">        <span class="hljs-keyword">try</span> {
</div><div class="hljs-line">            state = reducer(state, action);
</div><div class="hljs-line">        } <span class="hljs-keyword">catch</span> (_) { }
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">        <span class="hljs-comment">// 通知事件池中的方法执行</span>
</div><div class="hljs-line">        listeners.forEach(<span class="hljs-function"><span class="hljs-params">listener</span> =&gt;</span> {
</div><div class="hljs-line">            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> listener === <span class="hljs-string">"function"</span>) {
</div><div class="hljs-line">                listener()
</div><div class="hljs-line">            }
</div><div class="hljs-line">        });
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> action;
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 默认派发执行一次：设置状态初始值</span>
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> randomString = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">randomString</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.random().toString(<span class="hljs-number">36</span>).substring(<span class="hljs-number">7</span>).split(<span class="hljs-string">''</span>).join(<span class="hljs-string">'.'</span>);
</div><div class="hljs-line">    };
</div><div class="hljs-line">    dispatch({
</div><div class="hljs-line">        <span class="hljs-attr">type</span>: <span class="hljs-string">`@@redux/INIT<span class="hljs-subst">${randomString()}</span>`</span>
</div><div class="hljs-line">    });
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">        getState,
</div><div class="hljs-line">        subscribe,
</div><div class="hljs-line">        dispatch
</div><div class="hljs-line">    };
</div><div class="hljs-line">};
</div></code></pre>


<hr>

<h4 id="redux工程化">redux工程化</h4>
<p>redux工程化其实就是“按模块划分”</p>
<p><img longdesc="./1662053874303.png" width="300" alt="Alt text" title="" type="image/png"
    src=""
    class=""></p>

<p><code>action-types.js</code></p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">/* 投票 */</span>
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> VOTE_SUP = <span class="hljs-string">'VOTE_SUP'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> VOTE_OPP = <span class="hljs-string">'VOTE_OPP'</span>;
</div></code></pre>

<p><code>reducers</code></p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">// voteReducer.js</span>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> { VOTE_SUP, VOTE_OPP } <span class="hljs-keyword">from</span> <span class="hljs-string">'../action-types'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> _ <span class="hljs-keyword">from</span> <span class="hljs-string">'@/assets/utils'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">let</span> initialState = {
</div><div class="hljs-line">    <span class="hljs-attr">supNum</span>: <span class="hljs-number">10</span>,
</div><div class="hljs-line">    <span class="hljs-attr">oppNum</span>: <span class="hljs-number">5</span>
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">voteReducer</span>(<span class="hljs-params">state = initialState, action</span>) </span>{
</div><div class="hljs-line">    state = _.clone(<span class="hljs-literal">true</span>, state);
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { type, payload = <span class="hljs-number">1</span> } = action;
</div><div class="hljs-line">    <span class="hljs-keyword">switch</span> (type) {
</div><div class="hljs-line">        <span class="hljs-keyword">case</span> VOTE_SUP:
</div><div class="hljs-line">            state.supNum += payload;
</div><div class="hljs-line">            <span class="hljs-keyword">break</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">case</span> VOTE_OPP:
</div><div class="hljs-line">            state.oppNum += payload;
</div><div class="hljs-line">            <span class="hljs-keyword">break</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">default</span>:
</div><div class="hljs-line">    }
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> state;
</div><div class="hljs-line">};
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// index.js</span>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> { combineReducers } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> voteReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./voteReducer'</span>;
</div><div class="hljs-line"><span class="hljs-comment">/*</span>
</div><div class="hljs-line"><span class="hljs-comment"> state公共状态</span>
</div><div class="hljs-line"><span class="hljs-comment">   vote</span>
</div><div class="hljs-line"><span class="hljs-comment">     supNum: 10,</span>
</div><div class="hljs-line"><span class="hljs-comment">     oppNum: 5</span>
</div><div class="hljs-line"><span class="hljs-comment"> */</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> reducer = combineReducers({
</div><div class="hljs-line">    <span class="hljs-attr">vote</span>: voteReducer
</div><div class="hljs-line">});
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> reducer;
</div></code></pre>

<p><code>actions</code></p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">// voteAction.js</span>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> { VOTE_SUP, VOTE_OPP } <span class="hljs-keyword">from</span> <span class="hljs-string">'../action-types'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> voteAction = {
</div><div class="hljs-line">    support(payload) {
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">            <span class="hljs-attr">type</span>: VOTE_SUP,
</div><div class="hljs-line">            payload
</div><div class="hljs-line">        };
</div><div class="hljs-line">    },
</div><div class="hljs-line">    oppose() {
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">            <span class="hljs-attr">type</span>: VOTE_OPP
</div><div class="hljs-line">        };
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> voteAction;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// index.js</span>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> voteAction <span class="hljs-keyword">from</span> <span class="hljs-string">"./voteAction"</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> actions = {
</div><div class="hljs-line">    <span class="hljs-attr">vote</span>: voteAction
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> actions;
</div></code></pre>

<p><code>index.js</code></p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> { createStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> reducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">/* 创建STORE */</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> store = createStore(reducer);
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> store;
</div></code></pre>

<p>在组件中需要修改的地方</p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">// 获取指定模块的状态</span>
</div><div class="hljs-line"><span class="hljs-keyword">let</span> { supNum, oppNum } = store.getState().vote;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// 派发任务的时候</span>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> actions <span class="hljs-keyword">from</span> <span class="hljs-string">'@/store/actions'</span>;
</div><div class="hljs-line">...
</div><div class="hljs-line">store.dispatch(actions.vote.support(<span class="hljs-number">10</span>));
</div><div class="hljs-line">store.dispatch(actions.vote.oppose());
</div></code></pre>

<p><strong>combineReducers源码</strong></p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">combineReducers</span>(<span class="hljs-params">reducers</span>) </span>{
</div><div class="hljs-line">  <span class="hljs-keyword">const</span> reducerKeys = <span class="hljs-built_in">Reflect</span>.ownKeys(reducers);
</div><div class="hljs-line">  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">combination</span>(<span class="hljs-params">state = {}, action</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> nextState = {};
</div><div class="hljs-line">    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; reducerKeys.length; i++) {
</div><div class="hljs-line">      <span class="hljs-keyword">const</span> key = reducerKeys[i],
</div><div class="hljs-line">        reducer = reducerKeys[key];
</div><div class="hljs-line">      <span class="hljs-keyword">const</span> nextStateForKey = reducer(state[key], action);
</div><div class="hljs-line">      nextState[key] = nextStateForKey;
</div><div class="hljs-line">    }
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> nextState;
</div><div class="hljs-line">  }
</div><div class="hljs-line">}
</div></code></pre>

<hr>

<h4 id="react-redux">react-redux</h4>
<p>让redux在react项目中可以更简单的调用！</p>
<p><code>Provider：把store注册到上下文中</code></p>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> store <span class="hljs-keyword">from</span> <span class="hljs-string">'./store'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">root.render(
</div><div class="hljs-line">  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;<span class="hljs-name">Vote</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">  <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>
</div><div class="hljs-line">);
</div></code></pre>

<p><code>connect：把公共状态和派发任务当做属性传递给属性</code></p>
<ul>
  <li>
    <p>自动获取上下文中的store</p>
  </li>
  <li>
    <p>自动把“让组件更新的方法”注册到store事件池中</p>
  </li>
  <li>
    <p>mapStateToProps</p>
  </li>
  <li>
    <p>mapDispatchToProps</p>
  </li>
</ul>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> Vote = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Vote</span>(<span class="hljs-params">props</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { supNum, oppNum } = props;
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"vote-box"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        ...</span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(
</div><div class="hljs-line">    <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> state.vote;
</div><div class="hljs-line">    }
</div><div class="hljs-line">)(Vote);
</div></code></pre>
<pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> actions <span class="hljs-keyword">from</span> <span class="hljs-string">'@/store/actions'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteFooter = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteFooter</span>(<span class="hljs-params">props</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { support, oppose } = props;
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"footer"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{support}</span>&gt;</span>支持<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{oppose}</span>&gt;</span>反对<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(
</div><div class="hljs-line">    <span class="hljs-literal">null</span>,
</div><div class="hljs-line">    dispatch =&gt; {
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">            support() {
</div><div class="hljs-line">                dispatch(actions.vote.support(<span class="hljs-number">10</span>));
</div><div class="hljs-line">            },
</div><div class="hljs-line">            oppose() {
</div><div class="hljs-line">                dispatch(actions.vote.oppose());
</div><div class="hljs-line">            }
</div><div class="hljs-line">        }
</div><div class="hljs-line">    }
</div><div class="hljs-line">)(VoteFooter);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// 或者</span>
</div><div class="hljs-line">&lt;button onClick={support.bind(<span class="hljs-literal">null</span>, <span class="hljs-number">10</span>)}&gt;支持&lt;<span class="hljs-regexp">/button&gt;</span>
</div><div class="hljs-line"><span class="hljs-regexp">export default connect(</span>
</div><div class="hljs-line"><span class="hljs-regexp">    null,</span>
</div><div class="hljs-line"><span class="hljs-regexp">    actions.vote</span>
</div><div class="hljs-line"><span class="hljs-regexp">)(VoteFooter);</span>
</div></code></pre>

<h4 id="react-redux源码">react-redux源码</h4>
<pre class="prettyprint hljs-dark"><code class="hljs zephir"><div class="hljs-line">import { createContext, useContext, useMemo, useState, useLayoutEffect } from <span class="hljs-string">'react'</span>;
</div><div class="hljs-line">import { bindActionCreators } from <span class="hljs-string">'redux'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// 创建上下文对象</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> ThemeContext = createContext();
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// Provider</span>
</div><div class="hljs-line">export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Provider</span><span class="hljs-params">(props)</span> </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> (
</div><div class="hljs-line">        &lt;ThemeContext.Provider
</div><div class="hljs-line">            value={{
</div><div class="hljs-line">                store: props.store
</div><div class="hljs-line">            }}&gt;
</div><div class="hljs-line">            {props.children}
</div><div class="hljs-line">        &lt;/ThemeContext.Provider&gt;
</div><div class="hljs-line">    )
</div><div class="hljs-line">};
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// connect</span>
</div><div class="hljs-line">export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">connect</span><span class="hljs-params">(mapStateToProps, mapDispatchToProps)</span> </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (!mapStateToProps) {
</div><div class="hljs-line">        mapStateToProps = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapStateToProps</span><span class="hljs-params">()</span> </span>{
</div><div class="hljs-line">            <span class="hljs-keyword">return</span> {};
</div><div class="hljs-line">        };
</div><div class="hljs-line">    }
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (!mapDispatchToProps) {
</div><div class="hljs-line">        mapDispatchToProps = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapDispatchToProps</span><span class="hljs-params">()</span> </span>{
</div><div class="hljs-line">            <span class="hljs-keyword">return</span> {};
</div><div class="hljs-line">        };
</div><div class="hljs-line">    }
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HOC</span><span class="hljs-params">(Component)</span> </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Proxy</span><span class="hljs-params">(props)</span> </span>{
</div><div class="hljs-line">            <span class="hljs-keyword">let</span> { store } = useContext(ThemeContext),
</div><div class="hljs-line">                { getState, dispatch, subscribe } = store;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">            <span class="hljs-comment">// 处理状态</span>
</div><div class="hljs-line">            <span class="hljs-keyword">let</span> state = getState();
</div><div class="hljs-line">            state = useMemo(() =&gt; mapStateToProps(state), [state]);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">            <span class="hljs-comment">// 处理任务派发</span>
</div><div class="hljs-line">            <span class="hljs-keyword">let</span> dispatchToProps = useMemo(() =&gt; {
</div><div class="hljs-line">                <span class="hljs-keyword">if</span> (typeof mapDispatchToProps === <span class="hljs-string">'function'</span>) {
</div><div class="hljs-line">                    <span class="hljs-keyword">return</span> mapDispatchToProps(dispatch);
</div><div class="hljs-line">                }
</div><div class="hljs-line">                <span class="hljs-keyword">return</span> bindActionCreators(mapDispatchToProps, dispatch);
</div><div class="hljs-line">            }, [dispatch]);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">            <span class="hljs-comment">// 向事件池注入方法</span>
</div><div class="hljs-line">            <span class="hljs-keyword">const</span> [, forceUpdate] = useState(<span class="hljs-number">0</span>);
</div><div class="hljs-line">            useLayoutEffect(() =&gt; {
</div><div class="hljs-line">                <span class="hljs-keyword">return</span> subscribe(() =&gt; forceUpdate(+<span class="hljs-keyword">new</span> Date()));
</div><div class="hljs-line">            }, [subscribe]);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">            <span class="hljs-keyword">return</span> &lt;Component 
</div><div class="hljs-line">                {...props} 
</div><div class="hljs-line">                {...state} 
</div><div class="hljs-line">                {...dispatchToProps} 
</div><div class="hljs-line">            /&gt;
</div><div class="hljs-line">        }
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>
  </div>
</body>

</html>